import hashlib
import hmac
import json
import requests
import time
import urllib.parse
import sys
import base64

from coin.exchange.base.kr_rest.auth_base import AuthKey
from coin2.api_client.common import (SyncQueryer)
from enum import Enum

CONTENT_TYPE = 'Content-Type'
ACCESS_KEY = 'ACCESS-KEY'
ACCESS_SIGN = 'ACCESS-SIGN'
ACCESS_TIMESTAMP = 'ACCESS-TIMESTAMP'
ACCESS_PASSPHRASE = 'ACCESS-PASSPHRASE'
APPLICATION_JSON = 'application/json'

SPOT_ORDER_V1_URL = '/api/spot/v1/trade'

class BitgetAuth(requests.auth.AuthBase):
  def __init__(self, key):
    self._key = AuthKey.from_file(key)
    self._key.passphrase = self._key.get_value('passphrase')
    print()

  def get_sign(self, str_to_be_signed):
    signature = hmac.new(self._key.secret_key_bytes,
                         str_to_be_signed.encode(),
                         digestmod=hashlib.sha256)
    signature = base64.b64encode(signature.digest()).decode()
    return signature
  
  def __call__(self, req: requests.PreparedRequest):
    assert req.method in ('GET', 'POST', 'DELETE'), req.method
    timestamp = int(time.time() * 1000)
    parsed_result = urllib.parse.urlparse(req.url)
    if req.method == 'GET' and parsed_result.query:
      path = parsed_result.path + '?' + parsed_result.query
    else:
      path = parsed_result.path
    body = req.body.decode() if req.body else ''
    str_to_be_signed = ''.join([str(timestamp), req.method, path, body])
    headers = dict()
    headers[CONTENT_TYPE] = APPLICATION_JSON
    headers[ACCESS_KEY] = self._key.access_key
    headers[ACCESS_SIGN] = self.get_sign(str_to_be_signed)
    headers[ACCESS_TIMESTAMP] = str(timestamp)
    headers[ACCESS_PASSPHRASE] = self._key.passphrase
    req.headers.update(headers)
    req.prepare_headers(req.headers)

    # print(req.headers)
    # print(req.body)
    # print(req.url)

    return req


class BitgetPrivateClient():
  def __init__(self, key, mea):
    self._key = key
    self._auth = BitgetAuth(key)
    self._mea = mea  # be all one
    self._url = "https://api.bitget.com"
    self._query = SyncQueryer(api_host=self._url, auth=self._auth)
    if 'Spot' in mea:
      self._inst_type = "SPOT"
    elif 'Futures' in mea:
      self._inst_type = "FUTURES"
    else:
      assert False, "unsupported mea"

  def get_balance(self, symbol=''):
    method = "GET"
    path = '/api/spot/v1/account/assets'
    json = {
        "coin" : symbol
    }
    response = self._query.query(
        method=method, path=path, json=json)
    return response
  
  def get_open_order(self, symbol=''):
    method = "POST"
    path = SPOT_ORDER_V1_URL + '/open-orders'
    json = {
        "symbol" : symbol
    }
    response = self._query.query(
        method=method, path=path, json=json)
    return response
  
  def get_hist_order(self, symbol, after='', before='', limit=100):
    method = "POST"
    path = SPOT_ORDER_V1_URL + '/history'
    json = {}
    if symbol:
      json["symbol"] = symbol
      json["after"] = after
      json["before"] = before
      json["limit"] = limit
      response = self._query.query(
        method=method, path=path, json=json)
      return response
    else:
      assert False,  "pls check args "
    
  def submit_order(self, symbol, quantity, side, orderType, force, price='', clientOrderId=''):
    method = "POST"
    path = SPOT_ORDER_V1_URL + '/orders'
    json = {}
    if symbol and quantity and side and orderType and force:
      json["symbol"] = symbol
      json["price"] = price
      json["quantity"] = quantity
      json["side"] = side
      json["orderType"] = orderType
      json["force"] = force
      json["clientOrderId"] = clientOrderId
      response = self._query.query(
        method=method, path=path, json=json)
      return response
    else:
      assert False,  "pls check args "
  
  def cancel_orders(self, symbol, orderId):
    method = "POST"
    path = SPOT_ORDER_V1_URL + '/cancel-order'
    json = {}
    if symbol and orderId:
      json["symbol"] = symbol
      json["orderId"] = orderId
      response = self._query.query(
        method=method, path=path, json=json)
      return response
    else:
      assert False,  "pls check args "
  
  def cancel_all_orders_by_symbol(self, symbol):
    if symbol:
      resp = self.get_open_order(symbol)
      data = resp.json()["data"]
      while data:
        orderIds = []
        for order in data:
          orderIds.append(order['orderId'])
          if len(orderIds) >= 50:
            break
        print(f'cancel {len(orderIds)} orders')
        method = "POST"
        path = SPOT_ORDER_V1_URL + '/cancel-batch-orders'
        js = {'symbol': symbol, 'orderIds': orderIds}
        response = self._query.query(
        method=method, path=path, json=js)
        print(json.dumps(response.json(), indent=2))
        time.sleep(1)
        resp = self.get_open_order(symbol)
        data = resp.json()["data"]
    else:
      assert False,  "pls check args "
      


if __name__ == "__main__":
  key_path = sys.argv[1]
  config = {"key_path": key_path, "mea": "Spot.Bitget.v1"}
  bitget = BitgetPrivateClient(key_path, "Spot.Bitget.v1")
  # resp = bitget.get_balance("")
  # print(json.dumps(resp.json(), indent=2))
  resp = bitget.get_open_order("")
  print(json.dumps(resp.json(), indent=2))
  # resp = bitget.get_hist_order("ETHUSDT_SPBL")
  # print(json.dumps(resp.json(), indent=2))
  # resp = bitget.submit_order("ETHUSDT_SPBL", "0.005", "buy", "limit", "normal", "1000")
  # print(json.dumps(resp.json(), indent=2))
  # resp = bitget.cancel_orders("ETHUSDT_SPBL", "1080618390300041216")
  # print(json.dumps(resp.json(), indent=2))

  # for i in range(100):
  #  resp = bitget.submit_order("ETHUSDT_SPBL", "0.005", "buy", "limit", "normal", "1000")
  #  if resp.json()["code"] != "00000":
  #    print(json.dumps(resp.json(), indent=2))
  #    break
  #  time.sleep(0.05)
  # resp = bitget.get_open_order("ETHUSDT_SPBL")
  # data = resp.json()["data"]
  # print(" open order limit is ", len(data))
  # bitget.cancel_all_orders_by_symbol("ETHUSDT_SPBL")

